package org.dim.oa.controller;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.dim.oa.dto.LeaveDto;
import org.dim.oa.mapper.DictMapper;
import org.dim.oa.mapper.FormProcessMapper;
import org.dim.oa.mapper.LeaveMapper;
import org.dim.oa.po.DictEntity;
import org.dim.oa.po.FormProcessEntity;
import org.dim.oa.po.LeaveEntity;
import org.dim.oa.po.ServerResponse;
import org.dim.oa.service.ImageService;
import org.dim.oa.vo.ApproveVo;
import org.dim.oa.vo.LeaveVo;
import org.dim.oa.vo.TodoVo;
import org.flowable.engine.*;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.task.api.Task;
import org.flowable.task.api.history.HistoricTaskInstance;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.ResourceUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.util.*;

/**
 * Created by lmj on 2021/3/16.
 */
@RestController
@RequestMapping("/vue")
@Slf4j
public class VueLeaveController {
    @Autowired
    RepositoryService repositoryService;

    @Autowired
    RuntimeService runtimeService;

    @Autowired
    TaskService taskService;

    @Autowired
    LeaveMapper leaveDao;

    @Autowired
    FormProcessMapper formProcessDao;

    @Autowired
    DictMapper dictDao;

    @Autowired
    ProcessEngine processEngine;

    @Autowired
    ImageService imageService;

    @Autowired
    HistoryService historyService;

    @RequestMapping("/leave/list")
    public ServerResponse list(@RequestBody LeaveEntity leaveEntity) {
        QueryWrapper<LeaveEntity> leaveEntityQueryWrapper = new QueryWrapper<>();
        leaveEntityQueryWrapper.in("user_name",leaveEntity.getUserName());
        List<LeaveEntity> leaveEntities = leaveDao.selectList(leaveEntityQueryWrapper);
        return ServerResponse.success(leaveEntities);
    }

    @RequestMapping("/start")
    public ServerResponse start(@RequestBody LeaveVo leaveVo) {
        QueryWrapper<FormProcessEntity> formProcessEntityQueryWrapper = new QueryWrapper<>();
        FormProcessEntity byDictId= formProcessDao.selectOne(formProcessEntityQueryWrapper.eq("dict_id",leaveVo.getProcessType()));
        String pdfKey = byDictId.getPdfKey();
        Map<String, Object> variables = new HashMap<>();
        variables.put("day", leaveVo.getDay());
        //variables.put("flag",true);
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionKey(pdfKey).singleResult();
        //启动流程，提交表单（即向流程输入变量）
        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(processDefinition.getKey(), variables);
        Task task = taskService.createTaskQuery().processInstanceId(processInstance.getProcessInstanceId()).singleResult();
        taskService.complete(task.getId());
        LeaveEntity leaveEntity = new LeaveEntity();
        BeanUtils.copyProperties(leaveVo, leaveEntity);
        leaveEntity.setCurrentProcess(processInstance.getId());
        leaveEntity.setPdfKey(pdfKey);
        leaveEntity.setProInsId(processInstance.getId());
        leaveEntity.setCurTime(new Date());
        int insert = leaveDao.insert(leaveEntity);
        return ServerResponse.success(insert);
    }


    //查询待办
    @RequestMapping("/todo")
    public ServerResponse todo(@RequestBody TodoVo assign) {
        //组长去查询代办
        TaskService taskService = processEngine.getTaskService();
        //待办
        List<Task> tasks = taskService.createTaskQuery().taskAssignee(assign.getAssign()).list();

//        List<Map<String, Object>> mapList = new ArrayList<>();
        List<String> proInsIds = new ArrayList<>();
        Map<String, String> map = new HashMap<>();

        for (Task task : tasks) {
            proInsIds.add(task.getProcessInstanceId());
            map.put(task.getProcessInstanceId(), task.getId());
        }
        List<LeaveDto> result = new ArrayList<>();
        QueryWrapper<LeaveEntity> leaveEntityQueryWrapper = new QueryWrapper<>();
        List<LeaveEntity> allByProInsId = leaveDao.selectList(leaveEntityQueryWrapper.in("pro_ins_id", proInsIds));
        for (LeaveEntity leaveEntity : allByProInsId) {
            String taskId = map.get(leaveEntity.getProInsId());
            LeaveDto leaveDTO = new LeaveDto();
            leaveDTO.setTaskId(taskId);
            BeanUtils.copyProperties(leaveEntity, leaveDTO);
            result.add(leaveDTO);
        }
        return ServerResponse.success(result);
    }

    //组长审批
    @RequestMapping("/agree")
    public ServerResponse approve(@RequestBody ApproveVo approveVo) {
        Map<String, Object> variables = new HashMap<>();
        variables.put("flag", approveVo.getFlag());
        /**
         * taskId:任务id
         * variables：下一次任务所需要的参数
         * localScope：默认为false【variables默认是局部变量
         * 在complete的时候会先用本任务（exception）的（局部）变量，如果没有才会用流程变量（全局）】
         * taskService.complete(String taskId, Map<String,Object> variables, boolean localScope)
         */
        taskService.complete(approveVo.getTaskId(), variables);
        //variable都是针对processInstance的。
        //local可能是针对某个execution分支的，也可能针对task的。
        //taskService.setVariableLocal("flag","flag",true);
        QueryWrapper<LeaveEntity> leaveEntityQueryWrapper = new QueryWrapper<>();
        LeaveEntity byId = leaveDao.selectOne(leaveEntityQueryWrapper.eq("id",approveVo.getId()));
        byId.setStatus(approveVo.getFlag());
        leaveDao.updateById(byId);
        return ServerResponse.success("manager processed ok! apply agreed");
    }

    //查看流程进行图
    @GetMapping("/CurProImg")
    public void getProcessImage(String pdfKey, String proInsId, HttpServletResponse response) throws Exception {
        List<ProcessInstance> list = runtimeService.createProcessInstanceQuery().processDefinitionKey(pdfKey).list();
        boolean flag=true;
        for (ProcessInstance pi : list) {
            //System.out.println(pi.getId());
            if (pi.getId().equals(proInsId)) {
                flag=false;
                byte[] bytes = imageService.generateImageByProcInstId(pi.getId());
                response.setHeader("Content-type", "image/png;charset=UTF-8");
                response.setHeader("Content-disposition", "inline;");
                response.getOutputStream().write(bytes);
            }
        }
        if (flag){
            File  file = ResourceUtils.getFile("classpath:img/finish.jpg");
            FileInputStream fis = new FileInputStream(file);
            byte[]  bytes = new byte[(int) file.length()];
             fis.read(bytes);
            response.setHeader("Content-type", "image/jpg;charset=UTF-8");
            response.setHeader("Content-disposition", "inline;");
            response.getOutputStream().write(bytes);
        }
    }

    //查询已办
    @RequestMapping("/done")
    public ServerResponse done(String taskHandler) {
        //ArrayList<ApproveTaskDTO> doneList = new ArrayList<>();
        List<HistoricTaskInstance> list = historyService.createHistoricTaskInstanceQuery()
                //分配给角色
                //.taskCandidateGroup(userEntity.getRole())
                //分配给某个人
                .taskAssignee(taskHandler)
                .finished()
                .list();
        List<String> proInsIds = new ArrayList<>();
        for (HistoricTaskInstance hisTask : list) {
            proInsIds.add(hisTask.getProcessInstanceId());
        }
        QueryWrapper<LeaveEntity> leaveEntityQueryWrapper = new QueryWrapper<>();
        List<LeaveEntity> allByProInsId = leaveDao.selectList(leaveEntityQueryWrapper.in("pro_ins_id", proInsIds));
        return ServerResponse.success(allByProInsId);
    }

    /**
     * 删除流程定义
     */
    @RequestMapping("/delete")
    public ServerResponse delete(String deploymentId) {
        repositoryService.deleteDeployment(deploymentId, true);
        return ServerResponse.success("ok");
    }

    /**
     * 删除流程定义
     */
    @RequestMapping("/getDict")
    public ServerResponse getDict() {
        return ServerResponse.success(dictDao.selectList(new QueryWrapper<DictEntity>()));
    }

    /**
     * 更新流程定义
     * 【推荐】Activiti提供的流程定义是基于XML的，一旦发布完成后，若想对流程定义实现更改，只有一种办法，就是重新发布新的版本
     * 【直接不推荐】但有时，我们需要的是不让他发行新版本，只是希望修改其原来的Xml，如我们对分支节点进行条件设置。
     * 直接实现实现对流程定义的XML实现读写。只需要拿到流程定义的deployId或definitionId,通过对其act_ge_bytearray表实现更改，其定义内容存放于bytes_字段中。
     * https://www.liuhsb.cn/articles/2020/03/01/1583068655511.html
     */
    @RequestMapping("/deleteLeave")
    public ServerResponse deleteLeave(Integer leaveId) {
        leaveDao.deleteById(leaveId);
        return ServerResponse.success("ok");
    }
}
